package logica.product;

import java.util.ArrayList;
import java.util.List;

import logica.exceptions.DoesNotContainException;
import logica.exceptions.InvalidActionException;
import logica.exceptions.InvalidDataException;
import logica.exceptions.RequiredDataException;
import logica.interfaces.AuctionListener;
import logica.interfaces.ProductIF;

public abstract class AbstractProduct implements ProductIF {
	// o identificador do produto
	private String produtoId;

	// o login do dono do produto
	private String owner;

	// nome do produto
	private String name;

	// descricao do produto
	private String description;

	// identificador da categoria do produto
	private String categoryId;

	// status do produto
	private String status;

	// quantidade de produtos
	private int quantity;

	// quantidade minima de interessados
	private int quantityInteress;

	// preco inicial
	private double inicialPrice;

	// identifica o tipo do produto (simples ou composto)
	private String type;

	// lista de interessados no produto.
	private List<String> interessados;

	// interessados no produto - Observer
	private List<AuctionListener> auctionListeners;

	/**
	 * Construtor de um produto.
	 *
	 * @param owner
	 *            o login do dono do produto.
	 * @param name
	 *            nome do produto.
	 * @param description
	 *            descricao do produto.
	 * @param categoryId
	 *            identificador da categoria do produto.
	 * @param status
	 *            status do produto.
	 * @param quantity
	 *            quantidade de produtos.
	 * @param quantityInteress
	 *            quantidade minima de interessados.
	 * @param inicialPrice
	 *            preco inicial.
	 * @param type
	 *            identifica o tipo do produto (simples ou composto).
	 * @throws Exception
	 *             Se a entrada for invalida.
	 */
	public AbstractProduct(String id, String owner, String name,
			String description, String categoryId, String status, int quantity,
			int quantityInteress, double inicialPrice, String type)
			throws InvalidDataException, RequiredDataException {

		setOwner(owner);
		setName(name);
		setDescription(description);
		setCategoryId(categoryId);
		setStatus(status);
		setQuantity(quantity);
		setQuantityInteress(quantityInteress);
		setInicialPrice(inicialPrice);
		setType(type);
		setProductId(id);

		this.interessados = new ArrayList<String>();
		this.auctionListeners = new ArrayList<AuctionListener>();
	}

	public void addInterest(String login) {
		this.interessados.add(login);
	}

	/**
	 * Adiciona um listener para o produto.
	 *
	 * @param listener
	 *            Um listener de evento para interessados no inicio de um
	 *            leilao.
	 */
	public void addListener(AuctionListener listener) {
		this.auctionListeners.add(listener);
	}

	/**
	 * Retorna a categoria a qual o produto pertence
	 *
	 * @return String categoryId
	 */
	public String getCategoryId() {
		return categoryId + "";
	}

	/**
	 * Retorna a descricao do produto
	 *
	 * @return String description
	 */
	public String getDescription() {
		return description;
	}

	/**
	 * Retorna o codigo do produto
	 *
	 * @return String id
	 */
	public String getId() {
		return produtoId;
	}

	/**
	 * Retorna o preco inicial do produto
	 *
	 * @return double inicialPrice
	 */
	public double getInicialPrice() {
		return inicialPrice;
	}

	/**
	 * Retorna a lista dos interecados pelo produto
	 *
	 * @return List<String> interessados
	 */
	public List<String> getInterested() {
		return interessados;
	}

	/**
	 * Retorna a quantidade dos interecados pelo produto
	 *
	 * @return int interessados
	 */
	public int getInterestedQuantity() {
		return interessados.size();
	}

	/**
	 * Retorna o nome do produto
	 *
	 * @return String name
	 */
	public String getName() {
		return name;
	}

	/**
	 * Retorna o dono do produto
	 *
	 * @return String owner
	 */
	public String getOwner() {
		return owner;
	}

	/**
	 * Retorna a quantidade do produto
	 *
	 * @return int quantidade
	 */
	public int getQuantity() {
		return quantity;
	}

	/**
	 * Retorna a quantidade de interesses para o produto ir a leilao
	 *
	 * @return int quantidadeInteress
	 */
	public int getQuantityInteress() {
		return quantityInteress;
	}

	/**
	 * Retorna o status do produto
	 *
	 * @return String status
	 */
	public String getStatus() {
		return status;
	}

	/**
	 * Retorna o tipo do produto
	 *
	 * @return String type
	 */
	public String getType() {
		return type;
	}

	/**
	 * Seta o codigo do produto
	 *
	 * @param int
	 *            produtctId
	 * @throws InvalidDataException
	 */
	public void setProductId(String produtctId) throws InvalidDataException {
		if (produtctId.trim().equals(""))
			throw new InvalidDataException("product id");
		this.produtoId = produtctId;
	}

	/**
	 * Seta categoria do produto
	 *
	 * @param categoryId
	 * @throws InvalidDataException
	 */
	public void setCategoryId(String categoryId) throws InvalidDataException {
		int c = Integer.parseInt(categoryId);
		if (c < 0)
			throw new InvalidDataException("product category");
		this.categoryId = categoryId;
	}

	/**
	 * Seta a descricao do produto
	 *
	 * @param String
	 *            description
	 * @throws RequiredDataException
	 */
	public void setDescription(String description) throws RequiredDataException {
		if (description.equals(""))
			throw new RequiredDataException("product description");
		this.description = description;
	}

	/**
	 * Seta o status do produto
	 *
	 * @param String
	 *            status
	 * @throws RequiredDataException
	 */
	public void setInicialPrice(double inicialPrice)
			throws InvalidDataException {
		if (inicialPrice < 0)
			throw new InvalidDataException("inicial price");
		this.inicialPrice = inicialPrice;
	}

	/**
	 * Seta o nome do produto
	 *
	 * @param String
	 *            name
	 * @throws RequiredDataException
	 */
	public void setName(String name) throws RequiredDataException {
		if (name.equals(""))
			throw new RequiredDataException("product name");
		this.name = name;
	}

	/**
	 * Seta quantida do produto
	 *
	 * @param int
	 *            quantity
	 * @throws InvalidDataException
	 */
	public void setQuantity(int quantity) throws InvalidDataException {
		if (quantity < 0)
			throw new InvalidDataException("quantity");
		this.quantity = quantity;
	}

	/**
	 * Seta quantida de interesses pelo produto para que ele possa ir a leilao
	 *
	 * @param int
	 *            quantityInteress
	 * @throws InvalidDataException
	 */
	public void setQuantityInteress(int quantityInteress)
			throws InvalidDataException {
		if (quantityInteress < 0)
			throw new InvalidDataException("quantity interess");
		this.quantityInteress = quantityInteress;

	}

	/**
	 * Seta o status do produto
	 *
	 * @param String
	 *            status
	 * @throws RequiredDataException
	 */
	public void setStatus(String status) throws RequiredDataException {
		if (status.equals(""))
			throw new RequiredDataException("product status");
		this.status = status;
	}

	/**
	 * Seta o tipo do produto
	 *
	 * @param String
	 *            type
	 * @throws RequiredDataException
	 */
	public void setType(String type) throws RequiredDataException {
		if (type.equals(""))
			throw new RequiredDataException("product type");
		this.type = type;
	}

	/**
	 * Seta o nome do dono do produto
	 *
	 * @param String
	 *            owner
	 * @throws RequiredDataException
	 */
	public void setOwner(String owner) throws RequiredDataException {
		if (owner.equals(""))
			throw new RequiredDataException("product owner");
		this.owner = owner;

	}

	/**
	 * Testa o inicio de um anuncio de um leilao. Caso seja necessario, ele
	 * desencadeia o evento.
	 *
	 * @param aucOwner
	 *            O dono do leilao.
	 * @param aucDescription
	 *            A descricao do leilao.
	 * @param date
	 *            A data do leilao.
	 * @param beginTime
	 *            A hora de inicio do leilao.
	 * @param endTime
	 *            A hora de final do leilao.
	 */
	public void initEvent(String aucOwner, String aucDescription, String date,
			String beginTime, String endTime) {
		AuctionAnnouncementEvent auctionEvent = new AuctionAnnouncementEvent(
				aucOwner, aucDescription, this.description, date, beginTime,
				endTime, String.valueOf(this.inicialPrice));
		if (this.getInterestedQuantity() >= this.quantityInteress) {
			for (AuctionListener listener : this.auctionListeners) {
				listener.receiveEvent(auctionEvent);
			}
		}
	}

	// serao implementados diferentemente para cada filho da hierarquia
	public abstract void addItem(ProductIF idItem)
			throws InvalidActionException, InvalidDataException;

	public abstract boolean removeItem(ProductIF idItem)
			throws InvalidActionException, DoesNotContainException,
			InvalidDataException;
}